package cn.com.huzo.webapp.controller.workflow;

import huzofw.common.web.controller.BaseFormController;
import huzofw.model.entities.workflow.WorkFlowEntity;
import huzofw.model.entities.workflow.WorkFlowNodeEntity;
import huzofw.service.activiti.ActivitiManager;
import huzofw.service.workflow.WorkFlowManager;
import huzofw.service.workflow.WorkFlowNodeManager;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

/**
 * 定义工作流控制器
 *
 * @author 吴旭
 */
@Controller
@RequestMapping(value = "/workflow")
public class WorkFlowController extends BaseFormController {

    // <editor-fold defaultstate="collapsed" desc="属性">
    private final String uploadPath = "/opt/wwwroot/upload/workflow/bpms/deployments";

    @Resource(name = "ActivitiManager")
    private ActivitiManager _manager_activiti;

    @Resource(name = "WorkFlowManager")
    private WorkFlowManager _manager;

    @Resource(name = "WorkFlowNodeManager")
    private WorkFlowNodeManager _manager_node;
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="画面处理部分">
    /**
     * 跳转到流程部署一览画面
     *
     * @return
     */
    @RequestMapping("/process_def/list.html")
    public ModelAndView redirectProcessListWnd() {
        ModelAndView view = new ModelAndView();
        view.setViewName("workflow.process_def.list.def");
        return view;
    }

    /**
     * 跳转到流程上传部署画面
     *
     * @return
     */
    @RequestMapping("/process_def/deploy.html")
    public ModelAndView redirectProcessDeployWnd() {
        ModelAndView view = new ModelAndView();
        view.setViewName("popup.workflow.process_def.deploy.def");
        return view;
    }

    /**
     * 跳转到流程定义图显示画面
     *
     * @param key 流程名
     * @return
     */
    @RequestMapping("/process_def/{key}/diagram.html")
    public ModelAndView redirectProcessDefDiagramWnd(@PathVariable(value = "key") String key) {
        ModelAndView view = new ModelAndView();
        view.addObject("Key", key);
        view.setViewName("popup.workflow.process_def.diagram.def");
        return view;
    }

    /**
     * 跳转到流程跟踪图显示画面
     *
     * @param key 流程名
     * @return
     */
    @RequestMapping("/process_trace/{key}/diagram.html")
    public ModelAndView redirectProcessTraceDiagramWnd(@PathVariable(value = "key") String key) {
        ModelAndView view = new ModelAndView();
        view.addObject("Key", key);
        view.setViewName("popup.workflow.process_trace.diagram.def");
        return view;
    }

    /**
     * 跳转到流程定义一览画面
     *
     * @return
     */
    @RequestMapping("/workflow_def/list.html")
    public ModelAndView redirectListWnd() {
        ModelAndView view = new ModelAndView();
        view.setViewName("workflow.workflow_def.list.def");
        return view;
    }

    /**
     * 流程定义编辑画面
     * <p>
     * @param request 上下文请求
     * @param action 操作标志 1;增加 2：编辑
     * @param workFlowId 流程标识
     * @return
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/{action}/{workFlowId}/edit.html",
            method = {RequestMethod.GET})
    public ModelAndView redirectEditWnd(HttpServletRequest request, @PathVariable(value = "action") int action,
            @PathVariable(value = "workFlowId") Long workFlowId) throws Exception {
        // 设置功能号
        //request.setAttribute("ResourceNo", ResourceNo);
        // 设置角色号
        //request.setAttribute("RoleNo", RoleNo);

        ModelAndView view = new ModelAndView();
        view.addObject("action", action);
        view.addObject("workFlowId", workFlowId.toString());

        view.setViewName("workflow.workflow_def.edit.def");
        return view;
    }

    /**
     * 跳转到流程定义一览画面
     *
     * @return
     */
    @RequestMapping("/workflow_def/lines/list.html")
    public ModelAndView redirectNodeListWnd() {
        ModelAndView view = new ModelAndView();
        view.setViewName("popup.workflow.workflow_def/lines.list.def");
        return view;
    }

    /**
     * 弹出流程定义选择画面
     * <p>
     * @return
     */
    @RequestMapping("/workflow_def/choice.html")
    public ModelAndView redirectChoicePopupWnd() {
        ModelAndView view = new ModelAndView();
        view.setViewName("popup.workflow.workflow_def.choice.def");
        return view;
    }

    /**
     * 转到流程定义在线维护画面
     * <p>
     * @return
     */
    @RequestMapping("/workflow_def/online/edit.html")
    public ModelAndView redirectWorkFlowOnlineEditWnd() {
        ModelAndView view = new ModelAndView();
        view.setViewName("popup.workflow.workflow_def.online_edit.def");
        return view;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="流程定义数据处理部分">
    /**
     * 取得已经部署的工作流。
     *
     * @param criterion
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/process_def/fetchForPage.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Map<String, Object> fetchProcessForPage(@RequestBody Map<String, Object> criterion) throws Exception {
        return _manager_activiti.findProcessForPage(criterion);
    }

    /**
     * 删除已经部署的工作流。
     *
     * @param criterion
     * @return 删除后的数据。
     * @throws Exception
     */
    @RequestMapping(value = "/process_def/deleteDeployedProcess.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Map<String, Object> deleteDeployedProcess(@RequestBody Map<String, Object> criterion) throws Exception {
        return _manager_activiti.deleteDeployedFlow(criterion);
    }

    /**
     * 获取流程定义的图形显示
     * <p>
     * @param id 流程定义ID
     * @param response
     * @throws java.lang.Exception
     */
    @RequestMapping("/process_def/{id}/getdiagram.html")
    public void genFlowDefinitionDiagram(@PathVariable(value = "id") String id, HttpServletResponse response) throws Exception {
        _manager_activiti.genFlowDefinitionDiagram(response, id);
    }

    /**
     * 跟踪流程状态并用图形显示
     * <p>
     * @param executionId 流程运行ID
     * @param response
     * @throws java.lang.Exception
     */
    @RequestMapping("/process_trace/{executionId}/getdiagram.html")
    public void genFlowTraceDiagram(@PathVariable(value = "executionId") String executionId, HttpServletResponse response) throws Exception {
        _manager_activiti.genFlowTraceDiagram(response, executionId);
    }

    /**
     * 根据标识取得流程数据。
     *
     * @param key 流程标识
     * @return 流程及步骤数据。
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/fetchByKey.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Map<String, Object> fetchByKey(@RequestBody Long key) throws Exception {
        return _manager.fetchByHeaderKey(key);
    }

    /**
     * 得到全部流程定义分页数据。
     *
     * @param criterion 检索条件
     * @return 流程定义分页数据
     * @throws java.lang.Exception
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "/workflow_def/fetchForPage.html",
            method = RequestMethod.POST,
            produces = {"application/xml", "application/json"})
    public @ResponseBody
    Map<String, Object> fetchForPage(@RequestBody Map<String, Object> criterion) throws Exception {
        return _manager.fetchForPage(criterion);
    }

    /**
     * 批量保存或更新流程定义。
     *
     * @param data 要处理的流程定义数据列表
     * @return
     *
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/batch/save.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Integer batchSave(@RequestBody final Map<String, ? extends List<WorkFlowEntity>> data) throws Exception {
        Integer rowsAffected = 0;

        if (data.get("insertList").size() > 0) {
            rowsAffected = MapUtils.getInteger(_manager.batchInsert(data.get("insertList")), "RowsAffected");
        }
        if (data.get("updateList").size() > 0) {
            rowsAffected = MapUtils.getInteger(_manager.batchUpdate(data.get("updateList")), "RowsAffected");
        }

        return rowsAffected;
    }

    /**
     * 保存流程定义。
     *
     * @param instance 要增加或者编辑的的流程定义数据
     * @return 增加的数据主键
     *
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/save.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Long save(@RequestBody final WorkFlowEntity instance) throws Exception {
        if (instance.getWorkFlowId() != 0) {
            return _manager.update(instance).longValue();
        } else {
            return _manager.insert(instance);
        }
    }

    /**
     * 删除流程定义。
     *
     * @param criterion 流程定义标识
     * <p>
     * @return
     *
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/delete.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Map<String, Object> delete(@RequestBody final Map<String, Object> criterion) throws Exception {
        return _manager.delete(criterion);
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="流程步骤数据处理部分">
    /**
     * 得到全部流程步骤分页数据。
     *
     * @param criterion 检索条件
     * @return 流程定义分页数据
     * @throws java.lang.Exception
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "/workflow_def/lines/fetchForPage.html",
            method = RequestMethod.POST,
            produces = {"application/xml", "application/json"})
    public @ResponseBody
    Map<String, Object> fetchWorkFlowNodeForPage(@RequestBody Map<String, Object> criterion) throws Exception {
        return _manager_node.fetchForPage(criterion);
    }

    /**
     * 批量保存或更新流程步骤。
     *
     * @param data 要处理的流程步骤数据列表
     * @return
     *
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/lines/batch/save.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Map<String, Object> batchSaveWorkFlowNode(@RequestBody final Map<String, ? extends List<WorkFlowNodeEntity>> data) throws Exception {
        Map<String, Object> rtnValue = new HashMap();

        if (data.get("insertList").size() > 0) {
            rtnValue = _manager_node.batchInsert(data.get("insertList"));
        }
        if (data.get("updateList").size() > 0) {
            rtnValue = _manager_node.batchUpdate(data.get("updateList"));
        }

        return rtnValue;
    }

    /**
     * 增加单条流程步骤。
     *
     * @param instance 要增加的的流程步骤数据
     * @return 增加的数据主键
     *
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/lines/single/save.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Long saveOneWorkFlowNode(@RequestBody final WorkFlowNodeEntity instance) throws Exception {
        return _manager_node.insert(instance);
    }

    /**
     * 删除流程步骤。
     *
     * @param instance 流程定义标识
     * <p>
     * @return
     *
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/lines/delete.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Map<String, Object> deleteWorkFlowNode(@RequestBody final WorkFlowNodeEntity instance) throws Exception {
        return _manager_node.singleDelete(instance);
    }

    /**
     * 批量删除流程步骤。
     *
     * @param itemList 要删除的数据
     * @return 删除后的数据
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/lines/batch/delete.html",
            method = RequestMethod.POST)
    public @ResponseBody
    Map<String, Object> batchDelete(@RequestBody final List<WorkFlowNodeEntity> itemList) throws Exception {
        return _manager_node.batchDelete(itemList);
    }

    /**
     * 根据流程标识取得其操作步骤。
     *
     * @param flowKey 流程标识
     * @return 流程步骤
     * @throws java.lang.Exception
     */
    @RequestMapping(value = "/workflow_def/lines/fetchNodeByFlowKey.html",
            method = RequestMethod.POST)
    public @ResponseBody
    List<WorkFlowNodeEntity> fetchNodeByFlowKey(@RequestBody final Long flowKey) throws Exception {
        return _manager_node.fetchNodeByFlowKey(flowKey);
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="上传、部署流程文件处理部分">
    /**
     * 上传流程文件，部署工作流。
     *
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/process_def/upload.html",
            method = RequestMethod.POST,
            produces = {"application/xml", "application/json"})
    public @ResponseBody
    Map<String, Object> uploadProcess(MultipartHttpServletRequest request) throws Exception {
        Map<String, Object> result = new HashMap();

        Iterator<String> uploadFiles = request.getFileNames();
        if (!uploadFiles.hasNext()) {
            result.put("success", false);
            result.put("errorMsg", "没有上传文件。");
            return result;
        }

        // the directory to upload to uploadPath + dir;
        //String uploadDir = getServletContext().getRealPath(uploadPath);
        String uploadDir = uploadPath;
        // Create the directory if it doesn't exist
        File dirPath = new File(uploadDir);

        if (!dirPath.exists()) {
            dirPath.mkdirs();
        }
        while (uploadFiles.hasNext()) {
            try {
                MultipartFile mpf = request.getFile(uploadFiles.next());
                FileUtils.copyInputStreamToFile(mpf.getInputStream(), new File(uploadDir, mpf.getOriginalFilename()));
                String filename = mpf.getOriginalFilename();
                InputStream inputStream = mpf.getInputStream();
                _manager_activiti.deploymentFlow(filename, inputStream);
                result.put("success", true);
                result.put("successMsg", "流程部署成功。");
            } catch (Exception e) {
                result.put("success", false);
                result.put("errorMsg", e.getMessage());
            }
        }

        return result;
    }
    // </editor-fold>
}
